package offer

import (
	// "bp/cache"
	sqlc "bp/db/sqlc"
	memberCoupon "bp/internal/service/entity/member_coupon"
	offTransaction "bp/internal/service/entity/off_transaction"
	offTrial "bp/internal/service/entity/off_trial"
	"fmt"

	// "bp/internal/service/entity/promotion"
	// "bp/internal/service/param"
	// "bp/internal/service/com/offer"
	"bp/internal/util"
	"context"
)

// LockTransactionParam 锁定交易参数
type LockTransactionParam struct {
	BrandID       int64
	MemberID      int64
	OutTransNo    string
	TransactScene string
	OrderPtrs     []*ToLockTransactOrder
}

// DoTrial 试算优惠
func (s *OfferComServiceImp) LockTransaction(ctx context.Context, q *sqlc.Queries, ptr *LockTransactionParam) (
	off int32,
	offTransactionOrderPtrs []*OffTransactionOrder,
	transactionIDs []int64,
	err error) {
	slog := util.NewContextLogger(ctx, s.slog)

	offTrialPtrs, err := s.entityHub.OffTrialService.ListOffTrialPtrs(ctx, q, &offTrial.ListOffTrialPtrsParam{
		OutTransNo: ptr.OutTransNo,
		TrialScene: ptr.TransactScene,
	})
	if err != nil {
		return
	}

	// 按照每个order独立来算
	for _, orderPtr := range ptr.OrderPtrs {
		var offerItemPtrs []*OffTransactionOfferItem
		offTransactionPtr, offTransactionOfferItemStatPtrs, lockErr := s.lockTransactOrder(ctx, q,
			ptr.BrandID, ptr.MemberID, ptr.OutTransNo, ptr.TransactScene, orderPtr, offTrialPtrs)
		if lockErr != nil {
			err = lockErr
			return
		}
		off += offTransactionPtr.Off
		offerItemPtrs = s.MapOffTransactionOfferItemStatPtrsToOffTransactionOfferItemPtrs(offTransactionOfferItemStatPtrs, s.ConvOffTransactionOfferItemStatPtrToOffTransactionOfferItemPtr())
		offTransactionOrderPtrs = append(offTransactionOrderPtrs, &OffTransactionOrder{
			OwnerID:       offTransactionPtr.OwnerID,
			OutOrderNo:    offTransactionPtr.OutOrderNo,
			Off:           offTransactionPtr.Off,
			OfferItemPtrs: offerItemPtrs,
		})
		transactionID := offTransactionPtr.ID
		transactionIDs = append(transactionIDs, transactionID)
		slog.Infof("lockTransactOrder(%s) 交易(%d) ok", orderPtr.OutOrderNo, transactionID)
	}
	slog.Infof("LockTransaction ok")
	return
}

func (s *OfferComServiceImp) vldOrderCouponOffTrialsAndFreeze(ctx context.Context, q *sqlc.Queries,
	memberID int64,
	outTransNo string,
	outOrderNo string,
	couponOffTrialPtrs []*sqlc.OffTrial) (err error) {
	if len(couponOffTrialPtrs) == 0 {
		return
	}
	var couponSns []string

	for _, ptr := range couponOffTrialPtrs {
		memberCouponTrialInfoPtr, umerr := s.UnMarshalOfferItemTrialInfoOfMemberCoupon(ptr.OfferItemTrialInfo)
		if umerr != nil {
			err = umerr
			return
		}
		couponSns = append(couponSns, memberCouponTrialInfoPtr.Sn)
	}

	memberCouponPtrs, err := s.entityHub.MemberCouponService.ListMemberCouponsBySns(ctx, q, &memberCoupon.ListMemberCouponsBySnsParam{
		Sns:      couponSns,
		MemberID: memberID,
	})
	if err != nil {
		return
	}

	var abnormalCouponSn string
	ivs := util.ToGenericSlice(memberCouponPtrs)
	isAbnormal := util.Any(ivs, func(i interface{}) bool {
		v := i.(*sqlc.MemberCoupon)
		if v.MemberCouponStatus != string(sqlc.EmMemberCouponStatusNormal) {
			abnormalCouponSn = v.Sn
			return true
		}
		return false
	})
	if isAbnormal {
		err = fmt.Errorf("优惠券(%s)不可用", abnormalCouponSn)
		return
	}

	memberCouponIDs := util.MapToInt64(ivs, func(i interface{}) int64 {
		v := i.(*sqlc.MemberCoupon)
		return v.ID
	})

	err = s.entityHub.MemberCouponService.FreezeMemberCoupons(ctx, q, &sqlc.FreezeMemberCouponsParams{
		OutTransNo: sqlc.NSFromString(outTransNo),
		OutOrderNo: sqlc.NSFromString(outOrderNo),
		IDs:        memberCouponIDs,
	})
	if err != nil {
		return
	}
	s.slog.Infof("FreezeMemberCoupons ok")
	return
}

func (s *OfferComServiceImp) lockTransactOrder(ctx context.Context, q *sqlc.Queries,
	brandID int64,
	memberID int64,
	outTransNo string,
	transactScene string,
	orderPtr *ToLockTransactOrder,
	offTrialPtrs []*sqlc.OffTrial,
) (offTransactionPtr *sqlc.OffTransaction, offTransactionOfferItemStatPtrs []*sqlc.OffTransactionOfferItemStat, err error) {
	ownerID := orderPtr.OwnerID
	offTrialPtrsOfOwner := s.entityHub.OffTrialService.FilterOffTrialPtrs(offTrialPtrs, func(ot *sqlc.OffTrial) bool {
		return ot.OwnerID == ownerID
	})
	if len(offTrialPtrsOfOwner) == 0 {
		err = fmt.Errorf("锁定优惠交易和试算的owner不匹配")
		return
	}

	couponOffTrialPtrs, _ := s.entityHub.OffTrialService.SplitOffTrialPtrs(offTrialPtrsOfOwner, func(ot *sqlc.OffTrial) bool {
		return ot.OfferItemType == string(sqlc.EmOfferItemTypeCoupon)
	})
	err = s.vldOrderCouponOffTrialsAndFreeze(ctx, q, memberID, outTransNo, orderPtr.OutOrderNo, couponOffTrialPtrs)
	if err != nil {
		return
	}

	var outAfterSaleNo string = "0"
	ownerType := offTrialPtrsOfOwner[0].OwnerType

	offOfOwner := util.FoldLeftInt32(util.MapToInt32(util.ToGenericSlice(offTrialPtrsOfOwner), func(i interface{}) int32 {
		v := i.(*sqlc.OffTrial)
		return v.Off
	}), func(i1, i2 int32) int32 {
		return i1 + i2
	}, 0)

	offTransactionPtr, err = s.entityHub.OffTransactionService.UpsertOffTransaction(ctx, q, &sqlc.UpsertOffTransactionParams{
		BrandID:        brandID,
		OwnerType:      ownerType,
		OwnerID:        ownerID,
		OutTransNo:     outTransNo,
		OutOrderNo:     orderPtr.OutOrderNo,
		OutAfterSaleNo: outAfterSaleNo,
		TransactScene:  transactScene,
		Off:            offOfOwner,
	})
	if err != nil {
		return
	}

	s.slog.Infof("offTransactionPtr=>%+v", offTransactionPtr)

	orderItemPtrs := orderPtr.OrderItemPtrs
	var upsertOffTransactionDetailParamPtrs []*sqlc.UpsertOffTransactionDetailParams
	for _, orderItemPtr := range orderItemPtrs {
		upsertOffTransactionDetailParamPtrs = append(upsertOffTransactionDetailParamPtrs, &sqlc.UpsertOffTransactionDetailParams{
			BrandID:               offTransactionPtr.BrandID,
			OwnerType:             offTransactionPtr.OwnerType,
			OwnerID:               offTransactionPtr.OwnerID,
			MemberID:              offTransactionPtr.MemberID,
			TransactionID:         offTransactionPtr.ID,
			OutTransNo:            offTransactionPtr.OutTransNo,
			OutOrderNo:            offTransactionPtr.OutOrderNo,
			OutAfterSaleNo:        offTransactionPtr.OutAfterSaleNo,
			OutOrderDetailID:      orderItemPtr.DetailID,
			OutOrderDetailCnt:     orderItemPtr.DetailCnt,
			OutAfterSaleDetailID:  0,
			OutAfterSaleDetailCnt: 0,
			ItemID:                orderItemPtr.ItemID,
			ItemSpecID:            orderItemPtr.ItemSpecID,
			ItemPrice:             orderItemPtr.ItemPrice,
		})
	}
	err = s.entityHub.OffTransactionService.RefreshOffTransactionDetailsByOutTransNoAndOutOrderNo(ctx, q,
		&offTransaction.RefreshOffTransactionDetailsByOutTransNoAndOutOrderNoParam{
			OutTransNo:                           outTransNo,
			OutOrderNo:                           orderPtr.OutOrderNo,
			UpsertOffTransactionDetailParamsPtrs: upsertOffTransactionDetailParamPtrs,
		})
	if err != nil {
		return
	}

	var upsertOffTransactionOfferItemStatParamsPtrs []*sqlc.UpsertOffTransactionOfferItemStatParams
	for _, offTrialPtr := range offTrialPtrsOfOwner {
		upsertOffTransactionOfferItemStatParamsPtrs = append(upsertOffTransactionOfferItemStatParamsPtrs, &sqlc.UpsertOffTransactionOfferItemStatParams{
			BrandID:           offTransactionPtr.BrandID,
			OwnerType:         offTransactionPtr.OwnerType,
			OwnerID:           offTransactionPtr.OwnerID,
			MemberID:          offTransactionPtr.MemberID,
			TransactionID:     offTransactionPtr.ID,
			OutTransNo:        offTransactionPtr.OutTransNo,
			OutOrderNo:        offTransactionPtr.OutOrderNo,
			OutAfterSaleNo:    offTransactionPtr.OutAfterSaleNo,
			OfferItemType:     offTrialPtr.OfferItemType,
			OfferItemID:       offTrialPtr.OfferItemID,
			OfferItemStatInfo: offTrialPtr.OfferItemTrialInfo,
			Off:               offTrialPtr.Off,
		})
	}

	offTransactionOfferItemStatPtrs, err = s.entityHub.OffTransactionService.RefreshOffTransactionOfferItemStatsByOutTransNoAndOutOrderNo(ctx, q,
		&offTransaction.RefreshOffTransactionOfferItemStatsByOutTransNoAndOutOrderNoParam{
			OutTransNo: outTransNo,
			OutOrderNo: orderPtr.OutOrderNo,
			UpsertOffTransactionOfferItemStatParamsPtrs: upsertOffTransactionOfferItemStatParamsPtrs,
		})
	if err != nil {
		return
	}

	return
}
